feat(auth): brand the OAuth loopback callback pages + drop the Node floor to 22.12 [ENG-3406] - #8
Merged
Merged
Conversation
access_denied now renders its own "Connection canceled" page instead of the generic error page, and that branch had no assertion. Also pin down that a canceled page carries no error details — the cancel is deliberate, so there is nothing to report back to the user. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The consent page lost its native ▶ disclosure marker, gained a card top highlight and a tighter backdrop. The loopback page is meant to read as the same surface, so it gets the same four changes: marker off with a CSS-drawn chevron that turns on open, inset top highlight on the card, a narrower top wash, and a radial grid mask centred on the card instead of a linear fade that left a seam mid-page. Still self-contained: the chevron is drawn with borders, so no icon font, no extra markup and nothing new to fetch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Follows the consent page back to its original backdrop: the wide top wash and the plain top-to-bottom grid fade. The card-centred variant was tried and rejected. The chevron disclosure and the card's top highlight stay. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…npm package `engines.node` was raised from >=20 to >=24 in 7edf056 as a side effect of a dependency bump, not because any code needed Node 24. The only runtime gate in the tree was doctor.ts's REQUIRED_NODE_MAJOR; @types/node@^22 typechecks clean and the suite is 563/563 on Node 22.22.0. The real floor is commander@15's >=22.12.0. An overstated floor is not a warning, it is a silent downgrade. npm resolves an unpinned install to the newest version whose `engines` the current runtime satisfies, so `npm i -g meshy-cli` on Node 22 installed 0.1.3 — the last version declaring >=20 — without printing anything. Reproduced against the live registry. Users then read `meshy --version` as 0.1.3 and reported the CLI as stale; agents read `engines` and reported it as incompatible. Separately, the update notifier hardcoded `npm i -g meshy-cli@latest`. The same tree is also published as `@meshy-ai/cli`, both declare the same `meshy` / `meshy-cli` bins, and npm refuses to relink a bin owned by another package — so an alias user who followed the hint got `EEXIST: file already exists` and no upgrade. version.ts now exports PACKAGE_NAME from the same package.json read, and the registry URL, upgrade command and notice text all derive from it. - engines.node, .node-version, the CI check job and doctor's floor are all 22.12 - tests/version.test.ts pins engines.node to the floor doctor enforces - smoke matrix is [22, 24, 26]: the floor, the current line, the next one - README documents the bin collision, how to switch, and the 0.1.3 trap - decisions.md D-061 / D-062 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…n when piped
`meshy balance` typed at a terminal answered with raw JSON braces. Surveyed the
CLIs on this machine: `gh release list`, `npm view`, `kubectl config
get-contexts` and `docker` all render a human shape by default and keep the
machine shape behind `--json` / `-o json` / `--format`. `aws` is the
counterexample, and it is configurable. A CLI whose default face is JSON braces
is the outlier.
This changes the default, not the contract. Untyped `--format` now resolves to
`pretty` when `process.stdout.isTTY` and `json` otherwise. Every agent, script,
pipe, redirect, command substitution and CI run reaches the CLI through
something that is not a TTY, so the bytes they read are byte-identical to
before; `--format json` and `--json` still force it, and SKILL.md already told
agents to pass it.
Two things had to be cleared first:
- commander carried `.default("json")` on the option, so "not typed" and
`--format json` were indistinguishable. The default moved into
`parseOutputFormat`, and `runtime.ts`'s duplicate `normalizeFormat` is deleted
rather than taught the same rule a second time.
- legacy `-o <file>` renders through `emit()` with the same format, so a
TTY-derived `pretty` would have silently landed in a file every caller reads
back as JSON. `GlobalFlags.formatExplicit` records whether `--format` was
really typed; untyped writes JSON to a file whatever the terminal shows.
`--save-json` was never affected — it has its own writer.
Side effect, and the point: the update notifier's two channels finally separate.
`attachUpdateNotice` already skipped `pretty`, so a human gets one stderr line
instead of a `_notice` blob inside their output *and* the line; a pipe still
carries `_notice` in the JSON.
An empty collection now renders as `warnings: []` rather than a dangling key —
it is the default human face now, so the wart is worth the two lines.
Minor, not patch: the interactive default changed. Bumped 0.3.2 → 0.4.0.
decisions.md D-063 records the ceiling (renderPretty is a recursive key: value
dump; a real table renderer waits for a specific complaint).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…else Follows the TTY-aware default: once `pretty` is what a person actually sees, the output should look like the CLIs it sits next to. `src/internal/color.ts`, ~50 lines and no dependency — four SGR codes do not justify one. The decision table, in order: FORCE_COLOR (on, unless `0`), NO_COLOR (off), TERM=dumb (off), then whether the stream is a TTY. Both env vars are the cross-ecosystem conventions and users expect them to work here. Painted against the stream the text is going to, never a global flag: - stdout, `pretty` only; - stderr for the `error:` / `hint:` lines and the update hint, so `meshy ... | jq` still shows a red error while `2> log` stays clean; - `json` / `ndjson` take the painter and ignore it — pinned by a test, because this is the one that would silently corrupt every agent reading stdout; - anything written to a file renders unpainted: `--format pretty -o notes.txt` must not put control codes on disk. `render()` now defaults to the plain painter and only the two stdout call sites opt in. Palette kept small: keys dim, `null` dim, and whole-value state words (`ok`/`SUCCEEDED`/`true` green, `FAILED`/`error`/`false` red, `PENDING`/`skipped`/`IN_PROGRESS` yellow). Matched on the entire value, case insensitively, so a prompt reading "a failed robot" is never repainted. Version stays 0.3.2: the machine contract is byte-identical, so this rides the same patch as the Node floor fix. decisions.md D-064. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
1. Brand the OAuth loopback callback pages (ENG-3406)
The loopback callback used to return a 214-byte unstyled page. It now matches
the polished consent screens: Meshy wordmark, proper backdrop, distinct
success / canceled / failed states. Covered by
tests/oauth.test.ts.2. Drop the Node floor to 22.12 and stop naming the wrong npm package
engines.nodewas raised from>=20to>=24in 7edf056 as a side effect of adependency bump, not because any code needed Node 24. The only runtime gate in
the tree was
doctor.ts'sREQUIRED_NODE_MAJOR;@types/node@^22typechecksclean and the suite is 563/563 on Node 22. The real floor is
commander@15's>=22.12.0.An overstated floor is not a warning, it is a silent downgrade. npm resolves an
unpinned install to the newest version whose
enginesthe current runtimesatisfies — so
npm i -g meshy-clion Node 22 installed 0.1.3, the lastversion declaring
>=20, and printed nothing. Reproduced against the liveregistry. Users read
meshy --versionas 0.1.3 and reported the CLI as stale;agents read
enginesand reported it as incompatible.Separately, the update notifier hardcoded
npm i -g meshy-cli@latest. The sametree is also published as
@meshy-ai/cli, both declare the samemeshy/meshy-clibins, and npm refuses to relink a bin owned by another package — soan alias user who followed the hint got
EEXIST: file already existsand noupgrade.
version.tsnow exportsPACKAGE_NAMEfrom the same package.jsonread, and the registry URL, upgrade command and notice text derive from it.
engines.node,.node-version, the CIcheckjob anddoctor's floor are all 22.12tests/version.test.tspinsengines.nodeto the floordoctorenforces[22, 24, 26]: the floor, the current line, the next onedocs/skill-parity/decisions.mdD-061 / D-062Verification on Node 22.12.0 (the declared floor)
pnpm install --frozen-lockfile,typecheck, 563/563,build. Packed tarballinstalled globally: no EBADENGINE, both bins start,
doctorreportslocal_ready: true/node=ok,doctor --check-apireaches the live API,the no-credential path exits 3 with a valid
error.code: "auth"envelope onstdout, and the loopback OAuth server renders the new 16.8 KB branded cancel
page with the same v1 error envelope as the published build.
Version bumped to 0.3.2. Publishing is a separate manual
release.ymlrun.🤖 Generated with Claude Code